package com.devshephard.rpcframework.rpc.service.rpcservice.impl;

import com.devshephard.rpcframework.rpc.annotation.DoRpc;
import com.devshephard.rpcframework.rpc.util.HttpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.AsyncContext;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

@Slf4j
public class RpcServiceHttpImpl implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {

    /**
     * object类型
     */
    private Class<?> type;

    private HttpClientUtil httpClientUtil;

    /**
     * 服务提供者名称
     */
    private String name;

    private ApplicationContext applicationContext;

    public RpcServiceHttpImpl() {
        this.httpClientUtil = new HttpClientUtil();
    }


    @Override
    public Class<?> getObjectType() {
        return type;
    }

    @Override
    public Object getObject() {

        System.out.println(this.hashCode());

        ClassLoader loader = type.getClassLoader();
        Class<?>[] interfaces = new Class[]{type};

        Object obj = Proxy.newProxyInstance(loader, interfaces, (proxy, method, args) -> {

            //System.out.println(proxy.hashCode());

            HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();

            AsyncContext asyncContext = request.startAsync();

            DoRpc doRpc = method.getAnnotation(DoRpc.class);
            log.info("URL：{}", doRpc.value().replace("{id}", args[0].toString()));
            log.info(doRpc.afterHandlerClass().getMethods().toString());

            new Thread(() -> {
                try {

                    log.info(Thread.currentThread().getName() + "Execute HttpClient method...");



                    //TODO HttpClientUtil可能要考虑线程安全问题
                    String resultContent = httpClientUtil.createDefaultHttpClient(doRpc.value().replace("{id}", args[0].toString()));

                    asyncContext.getResponse().getWriter().write(resultContent);

                    final Method[] methods = doRpc.afterHandlerClass().getMethods();
                    for (Method mdItem : methods) {
                        if (mdItem.getName().equals(doRpc.afterHandlerMethod())) {
                               mdItem.invoke(null);
                        }
                    }

                    asyncContext.complete();

                } catch (IOException | IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            }, "Thread Son of " + Thread.currentThread().getName()).start();

            return args[0] + ",RPC已执行！";

        });

        return obj;
    }


    @Override
    public boolean isSingleton() {
        return false;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.hasText(name, "Name must be set");
    }

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        applicationContext = context;
    }

    public Class<?> getType() {
        return type;
    }

    public void setType(Class<?> type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
